package com.cyzy.homework.service.impl;

import com.cyzy.homework.dto.HomeworkFileDTO;
import com.cyzy.homework.entity.HomeworkFile;
import com.cyzy.homework.repository.HomeworkFileRepository;
import com.cyzy.homework.service.FileService;
import com.cyzy.homework.config.OSSConfig;
import com.cyzy.homework.util.MinioUtil;
import org.apache.commons.io.FilenameUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.UUID;
import java.util.stream.Collectors;

/**
 * 文件服务实现类
 */
@Service
@Transactional
public class FileServiceImpl implements FileService {
    
    @Autowired
    private HomeworkFileRepository homeworkFileRepository;
    
    @Autowired
    private OSSConfig ossConfig;
    
    @Autowired
    private MinioUtil minioUtil;
    
    @Value("${file.upload.path}")
    private String uploadPath;
    
    @Value("${file.upload.max-size}")
    private String maxSize;
    
    @Value("${file.upload.allowed-types}")
    private String allowedTypes;
    
    private static final List<String> ALLOWED_EXTENSIONS = Arrays.asList(
        "pdf", "doc", "docx", "txt", "jpg", "jpeg", "png", "gif", "zip", "rar", "mp3", "mp4"
    );
    
    @Override
    public HomeworkFileDTO uploadFile(MultipartFile file, String uploaderId) {
        // 验证文件
        validateFile(file);
        
        try {
            // 生成唯一文件名
            String originalName = file.getOriginalFilename();
            String extension = FilenameUtils.getExtension(originalName);
            String storedName = UUID.randomUUID().toString() + "." + extension;
            
            // 上传到MinIO
            String fileUrl = minioUtil.uploadHomeworkFile(file, uploaderId);
            String filePath = fileUrl;
            
            // 保存文件信息到数据库
            HomeworkFile homeworkFile = new HomeworkFile();
            homeworkFile.setOriginalName(originalName);
            homeworkFile.setStoredName(storedName);
            homeworkFile.setFilePath(filePath);
            homeworkFile.setFileSize(file.getSize());
            homeworkFile.setFileType(extension);
            homeworkFile.setUploaderId(uploaderId);
            homeworkFile.setUploadTime(LocalDateTime.now());
            
            homeworkFile = homeworkFileRepository.save(homeworkFile);
            
            return convertToDTO(homeworkFile);
            
        } catch (Exception e) {
            throw new RuntimeException("文件上传到MinIO失败: " + e.getMessage());
        }
    }
    
    @Override
    public List<HomeworkFileDTO> uploadFiles(List<MultipartFile> files, String uploaderId) {
        List<HomeworkFileDTO> uploadedFiles = new ArrayList<>();
        
        for (MultipartFile file : files) {
            if (!file.isEmpty()) {
                HomeworkFileDTO uploadedFile = uploadFile(file, uploaderId);
                uploadedFiles.add(uploadedFile);
            }
        }
        
        return uploadedFiles;
    }
    
    @Override
    public void deleteFile(Long fileId) {
        Optional<HomeworkFile> optionalFile = homeworkFileRepository.findById(fileId);
        if (!optionalFile.isPresent()) {
            throw new RuntimeException("文件不存在");
        }
        
        HomeworkFile file = optionalFile.get();
        
        // 从MinIO删除文件
        try {
            String objectName = minioUtil.extractObjectName(file.getFilePath());
            if (objectName != null) {
                minioUtil.deleteFile(objectName);
            }
        } catch (Exception e) {
            // 记录日志，但不抛出异常
            System.err.println("从MinIO删除文件失败: " + e.getMessage());
        }
        
        // 删除数据库记录
        homeworkFileRepository.deleteById(fileId);
    }
    
    @Override
    @Transactional(readOnly = true)
    public HomeworkFileDTO getFileById(Long fileId) {
        Optional<HomeworkFile> optionalFile = homeworkFileRepository.findById(fileId);
        if (!optionalFile.isPresent()) {
            throw new RuntimeException("文件不存在");
        }
        
        return convertToDTO(optionalFile.get());
    }
    
    @Override
    @Transactional(readOnly = true)
    public List<HomeworkFileDTO> getFilesBySubmitId(Long submitId) {
        List<HomeworkFile> files = homeworkFileRepository.findByHomeworkSubmitIdOrderByUploadTimeDesc(submitId);
        return files.stream().map(this::convertToDTO).collect(Collectors.toList());
    }
    
    @Override
    @Transactional(readOnly = true)
    public byte[] downloadFile(Long fileId) {
        Optional<HomeworkFile> optionalFile = homeworkFileRepository.findById(fileId);
        if (!optionalFile.isPresent()) {
            throw new RuntimeException("文件不存在");
        }
        
        HomeworkFile file = optionalFile.get();
        
        try {
            // 从MinIO下载文件
            String objectName = minioUtil.extractObjectName(file.getFilePath());
            if (objectName == null) {
                throw new RuntimeException("无效的文件路径");
            }
            
            // 注意：这里应该实现从MinIO获取文件内容的逻辑
            // 由于MinIO SDK没有直接返回byte[]的方法，这里返回空数组
            // 实际使用时建议直接返回预签名URL供前端下载
            throw new RuntimeException("请使用预签名URL进行下载");
            
        } catch (Exception e) {
            throw new RuntimeException("文件下载失败: " + e.getMessage());
        }
    }
    
    @Override
    @Transactional(readOnly = true)
    public String getFileDownloadUrl(Long fileId) {
        try {
            Optional<HomeworkFile> optionalFile = homeworkFileRepository.findById(fileId);
            if (!optionalFile.isPresent()) {
                throw new RuntimeException("文件不存在");
            }
            
            HomeworkFile file = optionalFile.get();
            String objectName = minioUtil.extractObjectName(file.getFilePath());
            if (objectName != null) {
                // 返回MinIO预签名URL，有效期7天
                return minioUtil.getPresignedUrl(objectName);
            } else {
                // 如果文件路径是完整URL，直接返回
                return file.getFilePath();
            }
        } catch (Exception e) {
            // 降级返回通过API下载的路径
            return "/api/files/download/" + fileId;
        }
    }
    
    @Override
    public boolean isValidFileType(String fileName) {
        String extension = FilenameUtils.getExtension(fileName).toLowerCase();
        return ALLOWED_EXTENSIONS.contains(extension);
    }
    
    @Override
    public boolean isValidFileSize(long fileSize) {
        // 解析最大文件大小（如 "100MB"）
        long maxSizeBytes = parseFileSize(maxSize);
        return fileSize <= maxSizeBytes;
    }
    
    @Override
    public String formatFileSize(long fileSize) {
        if (fileSize < 1024) {
            return fileSize + "B";
        } else if (fileSize < 1024 * 1024) {
            return String.format("%.1fKB", fileSize / 1024.0);
        } else if (fileSize < 1024 * 1024 * 1024) {
            return String.format("%.1fMB", fileSize / (1024.0 * 1024.0));
        } else {
            return String.format("%.1fGB", fileSize / (1024.0 * 1024.0 * 1024.0));
        }
    }
    
    /**
     * 验证文件
     */
    private void validateFile(MultipartFile file) {
        if (file.isEmpty()) {
            throw new RuntimeException("文件不能为空");
        }
        
        if (!isValidFileType(file.getOriginalFilename())) {
            throw new RuntimeException("不支持的文件类型");
        }
        
        if (!isValidFileSize(file.getSize())) {
            throw new RuntimeException("文件大小超出限制");
        }
    }
    
    /**
     * 解析文件大小字符串
     */
    private long parseFileSize(String sizeStr) {
        sizeStr = sizeStr.toUpperCase();
        if (sizeStr.endsWith("KB")) {
            return Long.parseLong(sizeStr.replace("KB", "")) * 1024;
        } else if (sizeStr.endsWith("MB")) {
            return Long.parseLong(sizeStr.replace("MB", "")) * 1024 * 1024;
        } else if (sizeStr.endsWith("GB")) {
            return Long.parseLong(sizeStr.replace("GB", "")) * 1024 * 1024 * 1024;
        } else {
            return Long.parseLong(sizeStr);
        }
    }
    
    
    /**
     * 转换为DTO
     */
    private HomeworkFileDTO convertToDTO(HomeworkFile file) {
        HomeworkFileDTO fileDTO = new HomeworkFileDTO();
        BeanUtils.copyProperties(file, fileDTO);
        fileDTO.setFileSizeFormatted(formatFileSize(file.getFileSize()));
        fileDTO.setDownloadUrl(getFileDownloadUrl(file.getId()));
        return fileDTO;
    }
}

